﻿using System.Diagnostics;
using System.Net;
using System.Threading;
using UtilZ.Dotnet.Ex.Base;
using UtilZ.Dotnet.Ex.DataStruct;
using UtilZ.Dotnet.Ex.Log;
using UtilZ.Tool.HostCore;
using UtilZ.Tool.HostPluginBase;

namespace UtilZ.Tool.HostAgent
{
    internal class Program
    {
        private static System.Threading.Mutex _globalMutex = null;

        static void Main(string[] args)
        {
            try
            {
                if (args != null &&
                    args.Length > 0 &&
                    (string.Equals(args[0], "q", StringComparison.OrdinalIgnoreCase)|| string.Equals(args[0], "-q", StringComparison.OrdinalIgnoreCase)))
                {
                    //有参数则为退出
                    SendExitRequest();
                    return;
                }

                if (!ProcessEx.TryCreataSingleProcessMutex(true, "171BF906-CA70-4C40-864B-AAB1D103BFAC", out _globalMutex))
                {
                    Console.WriteLine("Host服务已启动,不能重复启动,按任意键后程序退出.");
                    Console.ReadKey();
                    return;
                }

                InitLog();

                string protectAppPath = System.Configuration.ConfigurationManager.AppSettings["protectAppPath"];
                string checkIntervalStr = System.Configuration.ConfigurationManager.AppSettings["checkInterval"];
                int checkInterval;
                if (!int.TryParse(checkIntervalStr, out checkInterval))
                {
                    checkInterval = 1000;
                }

                string noRespondingMillisecondsTimeoutStr = System.Configuration.ConfigurationManager.AppSettings["noRespondingMillisecondsTimeout"];
                int noRespondingMillisecondsTimeout;
                if (!int.TryParse(noRespondingMillisecondsTimeoutStr, out noRespondingMillisecondsTimeout))
                {
                    noRespondingMillisecondsTimeout = 5000;
                }

                var appProtector = new ProcessMonitor(protectAppPath, checkInterval, noRespondingMillisecondsTimeout);
                using var hostBll = new HostBLL(appProtector, Exit);
                //hostBll.Test();
                hostBll.Start();
                if (EnvironmentEx.IsWindowPlatform())
                {
                    hostBll.HideConsole();
                }

                Console.WriteLine("q exit");
                ConsoleKeyInfo consoleKey;
                while (true)
                {
                    consoleKey = Console.ReadKey();
                    if (consoleKey.Key == ConsoleKey.Q)
                    {
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                Loger.Fatal(ex);
            }

            ReleaseMutex();
            Environment.Exit(0);
        }

        private static void ReleaseMutex()
        {
            if (_globalMutex != null)
            {
                _globalMutex.ReleaseMutex();
                _globalMutex.Dispose();
            }
        }


        private static void Exit()
        {
            try
            {
                _globalMutex.Dispose();
                Environment.Exit(0);
            }
            catch (Exception ex)
            {
                Loger.Error(ex);
            }
        }


        private static void SendExitRequest()
        {
            try
            {
                HttpClient httpClient = new HttpClient();
                httpClient.Timeout = TimeSpan.FromSeconds(300);
                string url = $"http://127.0.0.1:{Config.Instance.HttpPort}/api/v1/host/exit";
                Task<string> task = httpClient.GetStringAsync(url);
                task.Wait();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }


        private static AsynQueue<RedirectOuputArgs> _logShowQueue;
        private static void InitLog()
        {
            UtilZ.Dotnet.Ex.ZLog.ZLoger.OutputOption = UtilZ.Dotnet.Ex.ZLog.ZLogerOutputOptions.Loger;
            var redirectAppenderToUI = (RedirectAppender)Loger.GetAppenderByName(null, "RedirectToUI");
            if (redirectAppenderToUI != null)
            {
                var option = new AsynQueueOptions()
                {
                    AutoStart = true,
                    IsBackground = true,
                    Capcity = 1000,//缓存最多1000项
                    ThreadName = "日志输出到控制台线程",
                    FullMode = ContainerFullMode.DropOld
                };
                _logShowQueue = new AsynQueue<RedirectOuputArgs>(LogOutputConsoleCallback, option);
                redirectAppenderToUI.RedirectOuput += RedirectLogOutput;
            }
        }


        private static void LogOutputConsoleCallback(RedirectOuputArgs e)
        {
            ConsoleColor fontColor;
            string str;
            try
            {
                var item = e.Item;
                LRPCHelper.PublishLog(item);

                str = string.Format("{0} {1}", item.Time.ToString(LogConstant.DateTimeFormat), item.Content);
                switch (item.Level)
                {
                    case LogLevel.Trace:
                        fontColor = ConsoleColor.Gray;
                        break;
                    case LogLevel.Debug:
                        fontColor = ConsoleColor.Gray;
                        break;
                    case LogLevel.Info:
                        fontColor = ConsoleColor.White;
                        break;
                    case LogLevel.Warn:
                        fontColor = ConsoleColor.Yellow;
                        break;
                    case LogLevel.Error:
                        fontColor = ConsoleColor.Red;
                        break;
                    case LogLevel.Fatal:
                        fontColor = ConsoleColor.Red;
                        break;
                    default:
                        return;
                }
            }
            catch (Exception ex)
            {
                fontColor = ConsoleColor.Red;
                str = ex.Message;
            }

            var oldForegroundColor = Console.ForegroundColor;
            Console.ForegroundColor = fontColor;
            Console.WriteLine(str);
            Console.ForegroundColor = oldForegroundColor;
        }

        private static void RedirectLogOutput(object sender, RedirectOuputArgs e)
        {
            try
            {
                //添加到日志输出队列,为的是不阻塞线程
                _logShowQueue.Enqueue(e);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}